/*
 * faulty.c -- a module which generates an oops when read
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/cdev.h>

#include <asm/uaccess.h>

static dev_t devno;
static struct cdev *faulty;
static int faulty_major = 0;

ssize_t faulty_read(struct file *flip, char __user *buf, size_t count, loff_t *pos)
{
	int ret;
	char stack_buf[4];

	memset(stack_buf, 0xff, 20);

	if (count > 4)
		count = 4;

	ret = copy_to_user(buf, stack_buf, count);
	if (!ret)
		return count;
	return ret;
}

ssize_t faulty_write(struct file *flip, const char __user *buf, size_t count, loff_t *pos)
{
	*(int *)0 = 0;
	return 0;
}

static struct file_operations faulty_fops = {
	.owner = THIS_MODULE,
	.read  = faulty_read,
	.write = faulty_write
};

static int faulty_init(void)
{
	int result;

	result = alloc_chrdev_region(&devno, 0, 1, "faulty");
	faulty_major = MAJOR(devno);

	if (result < 0) {
                printk(KERN_WARNING "faulty: can't get major %d\n", faulty_major);
                return result;
        }
	
	faulty = cdev_alloc();
	faulty->ops = &faulty_fops;
	/* faulty->owner = THIS_MODULE; */
	result = cdev_add(faulty, devno, 1);
	if (result) {
		printk(KERN_ERR "faulty: Couldn't cdev_add, result=%d\n", result);
		return 1;
	}

	return 0;
}

static void faulty_cleanup(void)
{
	cdev_del(faulty);
	unregister_chrdev_region(devno, 1);
}

module_init(faulty_init);
module_exit(faulty_cleanup);

MODULE_AUTHOR("wangxy");
MODULE_LICENSE("GPL");
 
